<script lang="ts" setup>
import { computed, nextTick, onMounted, ref, watch } from 'vue';

import loader from '@monaco-editor/loader';
import * as monaco from 'monaco-editor';

import { useEditorStore } from '@/store';

import { configMonocaEditor, registerLanguage } from './init';

defineOptions({
  name: 'CodeDiffEditor',
});
const {
  ext = '.txt',
  height,
  modified,
  name,
  original,
  toolbarHeight = 36,
} = defineProps<{
  ext: string;
  height: number;
  modified: string;
  name: string;
  original: string;
  toolbarHeight: number;
}>();
const emits = defineEmits(['editorDiffDispose']);
loader.config({ monaco });
loader.config({ paths: { vs: 'monaco-editor/min/vs' } });
loader.config({
  'vs/nls': {
    availableLanguages: { '*': 'zh-cn' },
  },
});

registerLanguage();

const editorInstances = ref<Record<string, any>>({});
const editorModels = ref<Record<string, monaco.editor.IDiffEditorModel | null>>(
  {},
);
let editorInstance: monaco.editor.IStandaloneDiffEditor | undefined;
const editorStyle = computed(() => {
  return {
    height: `${height - toolbarHeight}px`,
  };
});
const editorStore = useEditorStore();
const config = computed<monaco.editor.IStandaloneEditorConstructionOptions>(
  () => {
    return editorStore.options;
  },
);
let $monaco: typeof monaco;

const languages = monaco.languages.getLanguages();
const language = computed(() => {
  return (
    languages.find((item) => item.extensions?.includes(ext))?.id || 'plaintext'
  );
});

onMounted(() => {
  console.log(name);
  const lang = language.value;
  nextTick(() => {
    // 初始化编辑器实例
    loader.init().then(async (_monacoEditor) => {
      $monaco = _monacoEditor;
      // 获取容器实例
      const editorContainer = document.querySelector(
        `.diff-editor-${name}`,
      ) as HTMLElement;

      const options = {
        language: lang,
        readOnly: true,
        ...config.value,
        diffCodeLens: true,
      } as monaco.editor.IStandaloneEditorConstructionOptions;

      setTimeout(async () => {
        if (editorContainer) {
          editorInstance = _monacoEditor.editor.createDiffEditor(
            editorContainer,
            options,
          );

          configMonocaEditor($monaco);

          // 源模型
          const originalModel = _monacoEditor.editor.createModel(
            original,
            lang,
          );
          // 修改的模型
          const modifiedModel = _monacoEditor.editor.createModel(
            modified,
            lang,
          );
          editorInstance?.setModel({
            modified: modifiedModel,
            original: originalModel,
          });
          editorInstances.value[name] = editorInstance;
          editorModels.value[name] = editorInstance.getModel();
        }
      }, 300);
    });
  });
});

const dispose = (name: string) => {
  if (editorInstances.value[name]) {
    try {
      $monaco.editor.getDiffEditors().forEach((editor) => {
        editor.dispose();
      });
      editorModels.value[name]?.modified?.dispose();
      editorModels.value[name]?.original?.dispose();
      editorInstances.value[name].dispose();
    } catch (error) {
      console.log(error);
    }
    delete editorModels.value[name];
    delete editorInstances.value[name];
    emits('editorDiffDispose');
  }
};


watch(
  () => config.value,
  (value) => {
    editorInstance?.updateOptions(value);
  },
  { deep: true, immediate: true },
);

watch(
  () => original,
  (newValue) => {
    editorInstance?.getModel()?.original.setValue(newValue);
  },
);

watch(
  () => modified,
  (newValue) => {
    editorInstance?.getModel()?.modified.setValue(newValue);
  },
);

defineExpose({
  dispose,
});
</script>
<template>
  <div class="wos-editor__content">
    <div :style="editorStyle" class="editor-container">
      <div :class="`diff-editor-${name}`" class="editor-container-box"></div>
    </div>
  </div>
</template>
<style lang="scss">
.editor-container-box {
  height: 100%;
}
</style>
